#include "mygpio.h"
#include "stm32f4xx_hal.h"
#include "gpio_irq.h"

T_GPIO_INFO * gpio_sets = NULL;
extern const T_GPIO_INFO g_gpio_sets[];
extern const T_MCU_IRQ_MAPPING g_irq_mappings[];

const T_GPIO_GROUP_MAPPING gpio_group_mapping_list[] = {
	{GROUP_GPIOA, GPIOA, NULL, 0},
	{GROUP_GPIOB, GPIOB, NULL, 0},
	{GROUP_GPIOC, GPIOC, NULL, 0},
	{GROUP_GPIOD, GPIOD, NULL, 0},
	{GROUP_GPIOE, GPIOE, NULL, 0},
	{GROUP_GPIOF, GPIOF, NULL, 0},
	{GROUP_GPIOG, GPIOG, NULL, 0},
	{GROUP_GPIOI, GPIOI, NULL, 0},
};

T_GPIO_IRQ_MAPPING gpio_irq_mapping_list[GPIO_TOTAL_NUM] = {0};

static int8_t gpio_judge(enum egpio_pin_name pin_name)
{
	int8_t ret = 0;
	
	if ((pin_name < 0) || (pin_name >= GPIO_TOTAL_NUM)) 
	{
		ret = -2;
		goto error;
	}
	
	if ((gpio_sets[pin_name].gpio_group == GROUP_INVALID) 
			|| (gpio_sets[pin_name].gpio_physical_pin == INVALID_GPIO_NUM)) 
	{
		ret = -3;
		goto error;
	}
	
	return ret;
	
error:
	printf("name=%d, ret=%d\r\n", pin_name, ret);
	return -1;
}

void set_gpio_toggle(enum egpio_pin_name pin_name)
{
    GPIO_TypeDef *gpio_type = NULL;
    
    if (gpio_judge(pin_name)) 
    {
        return;
    }

    gpio_type = gpio_group_mapping_list[gpio_sets[pin_name].gpio_group].gpio_type;
    HAL_GPIO_TogglePin(gpio_type, 1 << gpio_sets[pin_name].gpio_physical_pin);
}

int8_t get_gpio_val(enum egpio_pin_name pin_name, uint8_t *val)
{
    GPIO_TypeDef *gpio_type = NULL;

    if (gpio_judge(pin_name)) 
    {
        return -1;
    }

    gpio_type = gpio_group_mapping_list[gpio_sets[pin_name].gpio_group].gpio_type;
    
    // HAL库读取引脚状态不区分输入输出模式
    GPIO_PinState state = HAL_GPIO_ReadPin(gpio_type, 1 << gpio_sets[pin_name].gpio_physical_pin);
    
    if (state == GPIO_PIN_SET)
    {
        *val = 1;
    }
    else
    {
        *val = 0;
    }
    
    return 0;
}

int8_t set_gpio_level(enum egpio_pin_name pin_name, uint8_t level)
{
    GPIO_TypeDef *gpio_type = NULL;

    if (gpio_judge(pin_name)) 
    {
        return -1;
    }

    gpio_type = gpio_group_mapping_list[gpio_sets[pin_name].gpio_group].gpio_type;
    
    if (level == 1)
    {
        HAL_GPIO_WritePin(gpio_type, 1 << gpio_sets[pin_name].gpio_physical_pin, GPIO_PIN_SET);
    }
    else if (level == 0)
    {
        HAL_GPIO_WritePin(gpio_type, 1 << gpio_sets[pin_name].gpio_physical_pin, GPIO_PIN_RESET);
    }
    
    return 0;
}

int8_t set_gpio_cfg(enum egpio_pin_name pin_name, enum egpio_dir dir, enum egpio_level level, enum egpio_pupd pupd, enum eirq_type irq_type)
{
    int8_t ret = 0;
    uint32_t exit_line = 0;
    uint8_t exit_pin_source = 0;
    GPIO_TypeDef *gpio_type = NULL;
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    IRQn_Type irq_channel = NonMaskableInt_IRQn;
    
    gpio_type = gpio_group_mapping_list[gpio_sets[pin_name].gpio_group].gpio_type;
    
    // 配置GPIO基本参数
    GPIO_InitStruct.Pin = 1 << gpio_sets[pin_name].gpio_physical_pin;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    
    // 配置上下拉
    if (pupd == PULL_UP) 
    {
        GPIO_InitStruct.Pull = GPIO_PULLUP;
    } 
    else if (pupd == PULL_DOWN) 
    {
        GPIO_InitStruct.Pull = GPIO_PULLDOWN;
    } 
    else 
    {
        GPIO_InitStruct.Pull = GPIO_NOPULL;
    }
    
    if (dir == AFMOD) 
    {
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        HAL_GPIO_Init(gpio_type, &GPIO_InitStruct);
    } 
    else if (dir == OUTPUT) 
    {
        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
        
        if (level == GPIO_HIGH) 
        {
            HAL_GPIO_WritePin(gpio_type, GPIO_InitStruct.Pin, GPIO_PIN_SET);
        } 
        else if (level == GPIO_LOW) 
        {
            HAL_GPIO_WritePin(gpio_type, GPIO_InitStruct.Pin, GPIO_PIN_RESET);
        }
        
        HAL_GPIO_Init(gpio_type, &GPIO_InitStruct);
    } 
    else if (dir == INPUT) 
    {
        GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
        HAL_GPIO_Init(gpio_type, &GPIO_InitStruct);

        if (irq_type != NO_IRQ) 
        {
            switch (irq_type) 
            {
                case IRQ_FALLING:
                    GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
                    break;
                case IRQ_RISING:
                    GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
                    break;
                case IRQ_BOTH:
                    GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING;
                    break;
                default:
                    ret = -3;
                    goto error;
            }
            
            HAL_GPIO_Init(gpio_type, &GPIO_InitStruct);
            
            exit_line = 1 << gpio_sets[pin_name].gpio_physical_pin;
            exit_pin_source = gpio_sets[pin_name].gpio_physical_pin;
            
            switch (gpio_sets[pin_name].gpio_physical_pin) 
            {
                case 0:
                    irq_channel = EXTI0_IRQn;
                    break;
                case 1:
                    irq_channel = EXTI1_IRQn;
                    break;
                case 2:
                    irq_channel = EXTI2_IRQn;
                    break;
                case 3:
                    irq_channel = EXTI3_IRQn;
                    break;
                case 4:
                    irq_channel = EXTI4_IRQn;
                    break;
                case 9:
                    irq_channel = EXTI9_5_IRQn;
                    break;
            
                case 15:
                    irq_channel = EXTI15_10_IRQn;
                    break;
                default:
                    ret = -4;
                    goto error;
            }
            
            HAL_NVIC_SetPriority(irq_channel, 2, 2);
            HAL_NVIC_EnableIRQ(irq_channel);
        }
    }
    else 
    {
        ret = -5;
        goto error;
    }
    
    return 0;
    
error:
    printf("GPIO init error [%d] err=%d\r\n", pin_name, ret);
    return ret;
}


static void enable_gpio_clock(enum egpio_pin_name pin_name)
{
    unsigned char gpio_group;
    
    gpio_group = gpio_sets[pin_name].gpio_group;
	//printf("OPEN CLK :%d\r\n",gpio_group);

    if (gpio_group == GROUP_GPIOA) 
	{
        /* Port A Clock Gate Control: Clock enabled */
		__HAL_RCC_GPIOA_CLK_ENABLE();
    } 
	else if (gpio_group == GROUP_GPIOB) 
	{
        /* Port B Clock Gate Control: Clock enabled */
		__HAL_RCC_GPIOB_CLK_ENABLE();
    }
	else if (gpio_group == GROUP_GPIOC) 
	{
        /* Port C Clock Gate Control: Clock enabled */
		__HAL_RCC_GPIOC_CLK_ENABLE();
    }
	else if (gpio_group == GROUP_GPIOD) 
	{
        /* Port D Clock Gate Control: Clock enabled */
		__HAL_RCC_GPIOD_CLK_ENABLE();
    }
	else if (gpio_group == GROUP_GPIOE) 
	{
        /* Port E Clock Gate Control: Clock enabled */
		__HAL_RCC_GPIOE_CLK_ENABLE();
    }
	else if (gpio_group == GROUP_GPIOF) 
	{
        /* Port F Clock Gate Control: Clock enabled */
		__HAL_RCC_GPIOF_CLK_ENABLE();
    }
	else if (gpio_group == GROUP_GPIOG) 
	{
        /* Port G Clock Gate Control: Clock enabled */
		__HAL_RCC_GPIOG_CLK_ENABLE();
    }
	else if (gpio_group == GROUP_GPIOI) 
	{
        /* Port I Clock Gate Control: Clock enabled */
		__HAL_RCC_GPIOI_CLK_ENABLE();
    }
}

int8_t init_gpio(void)
{
	uint8_t i = 0;
	
	gpio_sets = (T_GPIO_INFO *)&(g_gpio_sets[0]);	
	for (i = 0; i < GPIO_TOTAL_NUM; ++i) 
	{
		gpio_irq_mapping_list[i].gpio_group = GROUP_INVALID;
		gpio_irq_mapping_list[i].gpio_virtual_pin = INVALID_GPIO_NUM;
	}
	
	for (i = 0; i < GPIO_TOTAL_NUM; ++i) 
	{
		if ((gpio_sets[i].gpio_physical_pin != INVALID_GPIO_NUM) && (gpio_sets[i].gpio_group != GROUP_INVALID)) 
		{
            enable_gpio_clock(i);
			set_gpio_cfg(i, gpio_sets[i].dir, !gpio_sets[i].gpio_active, gpio_sets[i].pupd, gpio_sets[i].irq_type);
		}
	}
	
	return 0;
}






